const Chain = require('../utils/Chain')

/**
 * 查询条件类型
 *
 * @class QueryType
 */
class QueryType {
  /**
   * @constructor
   * @param {object} query parse 的query实例
   * @param {object} prop 字段的配置
   * @param {string} key 字段名
   * @memberof QueryType
   */
  constructor (query, prop, key) {
    this.query = query
    this.prop = prop
    this.key = key
    this._onlyKey = ['exists', 'doesNotExist']

    this.setOnlyKey = this.setOnlyKey.bind(this)
    this.setBoolean = this.setBoolean.bind(this)
    this.setTargetClass = this.setTargetClass.bind(this)
    this.setDate = this.setDate.bind(this)
    this.setRange = this.setRange.bind(this)
    this.setContainIn = this.setContainIn.bind(this)
    this.setMatches = this.setMatches.bind(this)
    this.setNormal = this.setNormal.bind(this)
  }
  /**
   * 处理不需要查询条件的查询规则
   *
   * @returns
   * @memberof QueryType
   */
  async setOnlyKey () {
    if (this._onlyKey.includes(this.prop.op)) {
      this.query[this.prop.op]([this.key])
      return this.query
    }
    return 'next'
  }
  /**
   * 处理布尔值
   *
   * @returns
   * @memberof QueryType
   */
  async setBoolean () {
    // 当为equalTo时，合并布尔值的
    if (this.prop.type === 'Boolean') {
      if (!this.prop.value && this.prop.op === 'equalTo') {
        this.query.containedIn(this.key, [false, undefined])
      } else {
        this.query[this.prop.op](this.key, this.prop.value)
      }
      return this.query
    }
    return 'next'
  }
  /**
   * 设置pointer的查询条件
   *
   * @returns
   * @memberof QueryType
   */
  async setTargetClass () {
    if (this.prop.type === 'Pointer') {
      this.query.equalTo(this.key,new Parse.Object(this.prop.targetClass,{id:this.prop.value}))
      return this.query
    }
    return 'next'
  }
  /**
   * 设置Date类型的查询条件
   *
   * @returns
   * @memberof QueryType
   */
  async setDate () {
    if (this.prop.type === 'Date') {
      if (Array.isArray(this.prop.value)) {
        this.query.greaterThanOrEqualTo(this.key,new Date(this.prop.value[0]))
        this.query.lessThanOrEqualTo(this.key,new Date(this.prop.value[1]))
      } else if (this.prop.value instanceof Date) {
        this.query[this.prop.op](this.key, new Date(this.prop.value))
      }
      return this.query
    }
    return 'next'
  }
  /**
   * 设置范围查询
   *
   * @returns
   * @memberof QueryType
   */
  async setRange () {
    if (this.prop.op === 'range') {
      const value = this.prop.value.split('-')
      this.query.greaterThanOrEqualTo(this.key, +value[0])
      this.query.lessThanOrEqualTo(this.key, +value[1])
      return this.query
    }
    return 'next'
  }
  /**
   * 设置containeIn查询
   *
   * @returns
   * @memberof QueryType
   */
  async setContainIn () {
    if (['containedIn', 'notContainedIn'].includes(this.prop.op)) {
      const values = this.prop.value.split(',').map(item => this.prop.type === 'Number' ? +item : item)  // 如果为Number类型，转换为数字
      this.query[this.prop.op](this.key, values)
      return this.query
    }
    return 'next'
  }
  /**
   * 设置正则查询
   *
   * @returns
   * @memberof QueryType
   */
  async setMatches () {
    if (this.prop.op === 'matches') {
      const reg = new RegExp(this.prop.value)
      this.query.matches(this.key, reg)
      return this.query
    }
    return 'next'
  }
  /**
   * 设置普通查询
   *
   * @returns
   * @memberof QueryType
   */
  async setNormal () {
    this.query[this.prop.op](this.key, this.prop.type === 'Number' ? +this.prop.value : this.prop.value)  // 如果为数字，先转换为数字格式
    return this.query
  }

  async deepMatchesQuery() {
    if (this.key.indexOf('.') < 0) {
      return 'next'
    }
    const prop = this.key
    let className = this.prop.targetClass || this.query.className
    const keys = prop.split('.')
    const classes = [className]
    const schema = await Parse.Cloud.run('getSchemas')
    const schemaForId = {}
    schema.forEach(item => {
      schemaForId[item.className] = item.fields
    })
    for (let i = 0, len = keys.length; i < len; i++) {
      const key = keys[i]
      const item = schemaForId[className][key]
      if (item.type === 'Pointer') {
        className = item.targetClass
      } else if (item.type === 'Array') {
        try {
          const result = await new Parse.Query(className).exists(key).first()
          className = result.get(key)[0].className
        } catch (err) {
          console.error(err)
        }
      }
      classes.push(className)
    }
    let query = await QueryType.createQuery(new Parse.Query(classes.pop()), this.prop, keys.pop())
    for (let i = keys.length - 1; i >= 1; i--) {
      query = new Parse.Query(classes[i]).matchesQuery(keys[i], query)
    }
    this.query.matchesQuery(keys[0], query)
    return this.query
  }

  static async createQuery (query, prop, key) {
    const queryType = new QueryType(query, prop, key)
    const chain = new Chain(queryType.setOnlyKey)
    chain
      .setNextSuccessor(new Chain(queryType.deepMatchesQuery.bind(queryType)))
      .setNextSuccessor(new Chain(queryType.setBoolean))
      .setNextSuccessor(new Chain(queryType.setTargetClass))
      .setNextSuccessor(new Chain(queryType.setDate))
      .setNextSuccessor(new Chain(queryType.setRange))
      .setNextSuccessor(new Chain(queryType.setContainIn))
      .setNextSuccessor(new Chain(queryType.setMatches))
      .setNextSuccessor(new Chain(queryType.setNormal))

    return await chain.start()
  }
}
/**
 * 增加查询条件
 *
 * @class AddCondition
 */
class AddCondition {
  /**
   * @constructor
   * @param {object} query parse 的query实例
   * @param {object} condition 查询条件配置
   * @memberof AddCondition
   */
  constructor (query, condition) {
    this.query = query
    this.condition = condition
  }
  /**
   * 增加查询条件
   *
   * @returns
   * @memberof AddCondition
   */
  async _addQuery () {
    const props = this.condition.query
    if(props){
      const keys = Object.keys(props)
      for (let i = 0, len = keys.length; i < len; i++) {
        const key = keys[i]
        this.query = await QueryType.createQuery(this.query, props[key], key)
      }
    }
    return this
  }
  /**
   * 增加排序条件
   *
   * @returns
   * @memberof AddCondition
   */
  _addOrder () {
    const props = this.condition.order
    if (props) {
      let isFirst = true
      props.forEach(item => {
        if (item.sort=='asc') {
          if (isFirst) {
            isFirst = false
            this.query.ascending(item.prop)
          } else {
            this.query.addAscending(item.prop)
          }
        } else {
          if (isFirst) {
            isFirst = true
            this.query.descending(item.prop)
          } else {
            this.query.addDescending(item.prop)
          }
        }
      })
    }
    return this
  }
  /**
   * 增加include条件
   *
   * @returns
   * @memberof AddCondition
   */
  _addIncludes () {
    const props = this.condition.includes
    props.forEach(item => {
      this.query.include(item)
    })
    return this
  }
  /**
   * 获取最终的查询条件
   *
   * @returns
   * @memberof AddCondition
   */
  async getQuery () {
    if(!this.condition) return this.query

    const query = await this._addQuery()
    query._addOrder()._addIncludes()
    return this.query
  }
}

Parse.Cloud.define('getDataList', async (req, res) => {
  try {
    const { model, pageSize = 15, currentPage = 1, condition } = req.params
    let query = new Parse.Query(model)
    const from = pageSize * (currentPage-1)
    query.skip(from).limit(pageSize).addDescending('updatedAt')

    query = await new AddCondition(query, condition).getQuery()

    const qDataList = query.find({useMasterKey: true})
    const qCount = query.count({useMasterKey: true})
    const dataList = await qDataList
    const count = await qCount

    res.success({
      code: 1,
      total: count,   // 总数量
      totalPage: Math.ceil(count / pageSize),  // 总页数
      currentPage: currentPage,   // 当前页
      pageSize: pageSize,   // 每页数量
      data: dataList
    })
  } catch (err) {
    console.log(err)
    res.error(err)
  }
})
